<?php
/**
 * Created by sublime 3.
 * Auth: Inhere
 * Date: 14-9-28
 * Time: 10:35
 * Uesd: 主要功能是 hi
 */
namespace ulue\core\model;

use Debug;
use ulue\core\abstracts\AbstractCore;

abstract class AbstractModel extends AbstractCore implements \ArrayAccess, \IteratorAggregate
{
############################## property definition ##############################


    protected static $tableAliases  = [];       // 表别名设置数组

    // 模型场景
    private $_scenario;

    const  CREATE_SCENARIO  = 'create';
    const  UPDATE_SCENARIO  = 'update';
    // const  READ_SCENARIO    = 'create';
    // const  DELETE_SCENARIO  = 'create';


############################## db operate initialize ##############################

    public function rules()
    {
        return [];
    }

    public function relations()
    {
        return [];
    }

    /**
     * @return array|mixed
     */
    public function attrNames()
    {
        return $this->getTableSchema()->getColumnNames();
    }

    /**
     * @return \ulue\core\db\base\schema\Schema
     */
    static public function getTableSchema()
    {
    }

    /**
     * @return array
     */
    public function attrLabels()
    {
        return array(
            // 'name'=>'名称：',
            );
    }

    /**
     * @return array
     */
    public function getAttrLabels()
    {
        return array();
    }

    public function attrIsSafed($name)
    {
        # code...
    }

    public function attrIsActived($name)
    {
        # code...
    }

    /**
     * @return bool
     */
    public function attrIsRequired($name)
    {
        return true;
    }


////////////////////////////////////////// Scenario ///////////////////////////////////////

    /**
     * @param $value
     * @return $this
     */
    public function setScenario($value)
    {
        if ($value && is_string($value)) {
            $this->_scenario = $value;
        }

        return $this;
    }

    /**
     * @return mixed
     */
    public function getScenario()
    {
        return $this->_scenario;
    }

    public function scenarios()
    {
        # code...
    }

////////////////////////////////////////// Attribute ///////////////////////////////////////

    /**
     * 设置数据模型的属性值
     * @param array $attrs
     * @param bool $reportError 不存在的字段是否报错
     * @throws \DMissArgumentException
     * @return $this
     */
    public function setAttrs(array $attrs, $reportError=true) // setAttrs
    {
        # code...
        if ( is_array($attrs) ) {
            $names = $this->attrNames();

            foreach ($attrs as $name => $value) {

                if ( in_array($name,$names) ) {
                    $this->$name = $value;
                } else if ($reportError) {
                    throw new \DMissArgumentException( sprintf('模型 %s 不存在属性名(字段) %s', get_class($this), $name));
                }
            }
        }

        return $this;
    }

    /**
     * 获取数据模型的属性
     * @param array $names
     * @param array $except 获取时要排除的属性
     * @return mixed
     */
    public function getAttrs(array $names=[], array $except=[]) // getAttrs
    {
        $values = array();

        foreach ($this->attrNames() as $name) {
            if (in_array($name, $except)) {
                continue;
            }

            $values[$name] = $this->$name;
        }

        if ($names && is_array($names)) {
            $values_2 = array();

            foreach($names as $name) {
                $values_2[$name]=isset($values[$name]) ? $values[$name] : null;
            }

            return $values_2;
        }

        return $values;
    }

    /**
     * @param null $names
     * @return $this
     */
    public function unsetAttrs($names=null)
    {
        if($names===null) {
            $names=$this->attrNames();
        }

        foreach($names as $name) {
            $this->$name = null;
        }

        return $this;
    }

    public function getSafeAttrs(array $names=[], array $except=[])
    {
        # code...
    }

////////////////////////////////////////// Attribute ///////////////////////////////////////

    public function getId()
    {
        return get_class($this);
    }

    public function getClassname()
    {
        return dirname( $this->getId() );
    }

    public function getName()
    {
        return basename( $this->getId() );
    }


////////////////////////////////////////// array iterator ////////////////////////////////////////////

    /**
     * Defined by IteratorAggregate interface
     * Returns an iterator for this object, for use with foreach
     * @return \ArrayIterator
     */
    public function getIterator()
    {
        return new \ArrayIterator( $this->getAttrs() );
    }


    /**
     * Checks whether an offset exists in the iterator.
     * @param   mixed  $offset  The array offset.
     * @return  boolean  True if the offset exists, false otherwise.
     */
    public function offsetExists($offset)
    {
        return property_exists($this,$offset);
    }

    /**
     * Gets an offset in the iterator.
     * @param   mixed  $offset  The array offset.
     * @return  mixed  The array value if it exists, null otherwise.
     */
    public function offsetGet($offset)
    {
        return $this->$offset;
    }

    /**
     * Sets an offset in the iterator.
     * @param   mixed  $offset  The array offset.
     * @param   mixed  $value   The array value.
     * @return  void
     */
    public function offsetSet($offset, $value)
    {
        $this->$offset = $value;
    }

    /**
     * Unset an offset in the iterator.
     * @param   mixed  $offset  The array offset.
     * @return  void
     */
    public function offsetUnset($offset)
    {
        if (isset($this->$offset)) {
            $this->$offset = null;
        }

        if (isset($this->_attrs[$offset])) {
            $this->_attrs[$offset] = null;
        }
    }

}